Skip to content

FE-1559: Adopt the worksheet focus layer in the Simulate view tables - #9446

Open
kube wants to merge 1 commit into
claude/fe-1545-sidebar-focus-layerfrom
claude/simulate-tables-focus-layer
Open

FE-1559: Adopt the worksheet focus layer in the Simulate view tables#9446
kube wants to merge 1 commit into
claude/fe-1545-sidebar-focus-layerfrom
claude/simulate-tables-focus-layer

Conversation

@kube

@kube kube commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

🌟 What is the purpose of this PR?

Stacked on #9420. Adopt the worksheet keyboard-flow layer in the Simulate-mode tables — the scenarios, experiments, optimizations, and metrics lists share one Table component whose every row was its own Tab stop with no arrow keys, and whose single click opened the drawer with no way to select a row without opening it.

🔗 Related links

🔍 What does this change?

  • Table delegates row focus to useFocusStops: each table is one Tab stop with a roving tabindex, and ArrowUp/ArrowDown walk the rows.
  • Activation is select-first (useSelectFirstActivation): the first click selects (focuses) a row, a click on the selected row — or Enter/Space — calls onRowSelect and opens the drawer. The focused row shows the inset ring on any focus, not only :focus-visible, so pointer users see the selection.
  • The unused renderActions per-row action-column API is deleted (no caller existed).
  • Tables without onRowSelect (the optimization steps table) stay inert, as before.
  • All four Simulate views inherit the behaviour with no changes of their own.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • modifies an npm-publishable library and I have added a changeset file(s)

📜 Does this require a change to the docs?

The changes in this PR:

  • require changes to docs which are made as part of this PR

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

  • Selecting a scenario row does not (yet) bind to the simulation's current scenario (SimulationContext.selectedScenarioId) — today that is only settable from the Simulation Settings picker. Select-first creates the natural slot for it; wiring it up is a product decision left for a follow-up.

🐾 Next steps

  • Decide whether first-click selection in the Scenarios list should set the current scenario, and wire it if so.

🛡 What tests cover this?

  • New table.test.tsx: one Tab stop with roving tabindex, arrow-key row walking, select-first click activation, Enter/Space activation, and inert rows without onRowSelect.
  • focus-flow.test.tsx (below in the stack) covers the underlying movement contract.

❓ How to test this?

  1. yarn dev, switch the top-bar mode to Simulate.
  2. Tab into the Scenarios list (one stop), walk rows with ArrowUp/ArrowDown.
  3. Click a row once — it selects (inset ring) without opening; click it again (or press Enter) — the drawer opens.
  4. Same behaviour in the Experiments and Optimizations tabs; the steps table inside an optimization drawer stays non-interactive.

The tables' visuals are unchanged apart from the focus ring; existing docs screenshots stay valid.

🤖 Generated with Claude Code

@kube kube self-assigned this Aug 30, 2026
@vercel

vercel Bot commented Aug 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview Aug 31, 2026 12:53am
petrinaut Ready Ready Preview Aug 31, 2026 12:53am
petrinaut-docs Ready Ready Preview Aug 31, 2026 12:53am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Aug 31, 2026 12:53am

Request Review

@cursor

cursor Bot commented Aug 30, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Localized UI interaction change in a shared table component with tests and docs; no auth, data, or simulation logic changes.

Overview
Simulate-mode list tables (scenarios, experiments, optimizations, metrics) now use the same keyboard and pointer model as worksheet surfaces, via shared hooks on the shared Table component.

Table is a single Tab stop with roving tabindex (useFocusStops); ArrowUp / ArrowDown move between rows. Opening a row is select-first (useSelectFirstActivation): the first click focuses the row (inset ring on any focus, not only :focus-visible); a second click on the focused row or Enter / Space calls onRowSelect (e.g. open the drawer). Tables without onRowSelect stay non-focusable. The unused per-row renderActions column API is removed.

Docs for scenarios and experiments describe the new list interaction. table.test.tsx covers roving tabindex, arrows, select-first clicks, keyboard activation, and inert mode.

Reviewed by Cursor Bugbot for commit 182e002. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 182e002. Configure here.

<div
aria-colcount={columnCount}
ref={onRowSelect ? attach : undefined}
aria-colcount={columns.length}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interactive table keeps static table role

Medium Severity

Rows are now a single Tab stop with ArrowUp/ArrowDown as the only way to reach the others, but the widget still uses role="table" and role="cell". Screen readers treat that as a static table and intercept arrow keys, so assistive-tech users can land on the first row and cannot walk or activate the rest. The sibling spreadsheet that uses the same focus hooks exposes role="grid" and role="gridcell" for this reason.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 182e002. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

1 participant